package com.fowo.api.common.meta;

import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.DeserializationFeature;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.springframework.core.io.ClassPathResource;

import java.io.InputStream;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * 用于读取 resource/meta-data.json 内容
 * @author yl_ls
 */
@SuppressWarnings("unused")
public final class MetaDataObjects {
    private static List<MetaDataObject> objects;

    /**
     * 获取项目对象定义数据
     * @return 项目对象定义数据
     */
    public static synchronized List<MetaDataObject> getObjects() {
        if (objects == null) {
            List<MetaDataObject> baseObjects, userObjects = null;
            try(InputStream inputStream = new ClassPathResource("meta-data.json").getInputStream()) {
                ObjectMapper objectMapper = new ObjectMapper();
                objectMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
                baseObjects = objectMapper.readValue(inputStream, new TypeReference<List<MetaDataObject>>() { });
            } catch (Exception e) {
                throw new RuntimeException("读取对象定义数据失败！");
            }
            ClassPathResource userMetaDataResource = new ClassPathResource("user-meta-data.json");
            if (userMetaDataResource.exists()) {
                try(InputStream inputStream = new ClassPathResource("user-meta-data.json").getInputStream()) {
                    ObjectMapper objectMapper = new ObjectMapper();
                    objectMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
                    userObjects = objectMapper.readValue(inputStream, new TypeReference<List<MetaDataObject>>() { });
                } catch (Exception e) {
                    throw new RuntimeException("读取用户对象定义数据失败！");
                }
            }
            objects = new ArrayList<>();
            objects.addAll(baseObjects);
            if (userObjects != null) {
                objects.addAll(userObjects);
            }
        }
        return objects;
    }

    private static final ThreadLocal<Map<String, MetaDataObject>> LOCAL_NAME_OBJECT_MAP = new ThreadLocal<>();

    /**
     * 使用本地线程 Map 提供高性能的对象元数据访问
     * @param objectName 对象名称
     * @return 对象元数据，不存在返回 null
     */
    public static MetaDataObject getObject(String objectName) {
        Map<String, MetaDataObject> nameObjectMap = LOCAL_NAME_OBJECT_MAP.get();
        if (nameObjectMap == null) {
            List<MetaDataObject> allObjects = getObjects();
            nameObjectMap = new HashMap<>(allObjects.size());
            for (MetaDataObject object : allObjects) {
                nameObjectMap.put(object.getName(), object);
            }
            LOCAL_NAME_OBJECT_MAP.set(nameObjectMap);
        }
        return nameObjectMap.get(objectName);
    }
}
